/*
 * File Name:               Texture2DExtension.cs
 * 
 * Description:             普通类
 * Author:                  lisiyu <576603306@qq.com>
 * Create Date:             2016/12/26
 */

using UnityEngine;

public static class Texture2DExtension
{
    /// <summary>
    /// 复制2d纹理
    /// </summary>
    /// <param name="src"></param>
    /// <param name="mipmap"></param>
    /// <param name="linear"></param>
    /// <returns></returns>
    public static Texture2D copy(this Texture2D src, bool mipmap = false, bool linear = false)
    {
        Texture2D ret = new Texture2D(src.width, src.height, src.format, mipmap, linear);

        ret.SetPixels(src.GetPixels());

        return ret;
    }

    /// <summary>
    /// 缩放
    /// </summary>
    /// <param name="src"></param>
    /// <param name="sizeX"></param>
    /// <param name="sizeY"></param>
    /// <returns></returns>
    public static Texture2D resize(this Texture2D src, int sizeX, int sizeY)
    {
        if (src.width == sizeX && src.height == sizeY) return src;

        var ret = new Texture2D(sizeX, sizeY, src.format, false);

        float scaleX = 1f * src.width / sizeX;
        float scaleY = 1f * src.height / sizeY;

        for (int i = 0; i < sizeX; i++)
        {
            for (int j = 0; j < sizeY; j++)
            {
                ret.SetPixel(i, j, src.GetPixel(Mathf.CeilToInt(i * scaleX), Mathf.CeilToInt(j * scaleY)));
            }
        }

        return ret;
    }

    /// <summary>
    /// 双线性缩放图片
    /// </summary>
    /// <param name="src"></param>
    /// <param name="sizeX"></param>
    /// <param name="sizeY"></param>
    /// <returns></returns>
    public static Texture2D resizeBilinear(this Texture2D src, int sizeX, int sizeY)
    {
        if (src.width == sizeX && src.height == sizeY) return src;

        var ret = new Texture2D(sizeX, sizeY, src.format, false);
        var pixels = ret.GetPixels();

        var xFactor = 1f / sizeX;
        var yFactor = 1f / sizeY;

        for (int j = 0; j < sizeY; j++)
        {
            for (int i = 0; i < sizeX; i++)
            {
                pixels[i + j * sizeX] = src.GetPixelBilinear(i * xFactor, j * yFactor);
            }
        }

        ret.SetPixels(pixels);

        return ret;
    }

    public static Texture2D resizeBilinear(this Texture2D src, TextureFormat format, int sizeX, int sizeY, int margin)
    {
        if (src.width == sizeX && src.height == sizeY) return src;

        var ret = new Texture2D(sizeX, sizeY, format, false);
        var pixels = ret.GetPixels();

        var xFactor = 1f / sizeX;
        var yFactor = 1f / sizeY;

        for (int j = 0; j < sizeY; j++)
        {
            for (int i = 0; i < sizeX; i++)
            {
                if (i >= margin && i < sizeX - margin && j >= margin && j < sizeY - margin)
                {
                    pixels[i + j * sizeX] = src.GetPixelBilinear(i * xFactor, j * yFactor);
                }
                else
                {
                    pixels[i + j * sizeX] = new Color(1, 1, 1, 0);
                }
            }
        }

        ret.SetPixels(pixels);

        return ret;
    }

    /// <summary>
    /// 缩放
    /// </summary>
    /// <param name="src"></param>
    /// <param name="scale"></param>
    /// <returns></returns>
    public static Texture2D scale(this Texture2D src, float scale)
    {
        if (scale == 1) return src;

        var width = src.width;
        var height = src.height;

        int sizeX = Mathf.CeilToInt(width * scale);
        int sizeY = Mathf.CeilToInt(height * scale);

        var ret = new Texture2D(sizeX, sizeY, src.format, false);

        var fSizeX = (float)sizeX;
        var fSizeY = (float)sizeY;
        for (int i = 0; i < sizeX; i++)
        {
            for (int j = 0; j < sizeY; j++)
            {
                ret.SetPixel(i, j, src.GetPixel(Mathf.CeilToInt(i / fSizeX * width), Mathf.CeilToInt(j / fSizeY * height)));
            }
        }

        return ret;
    }

    /// <summary>
    /// 双线性缩放图片
    /// </summary>
    /// <param name="src"></param>
    /// <param name="scale"></param>
    /// <returns></returns>
    public static Texture2D scaleBilinear(this Texture2D src, float scale)
    {
        if (scale == 1f) return src;
        if (src.width == 0 || src.height == 0)
            return src;

        var ret = new Texture2D(Mathf.CeilToInt(src.width * scale), Mathf.CeilToInt(src.height * scale), src.format, false);
        var pixels = ret.GetPixels();

        var sizeX = ret.width;
        var sizeY = ret.height;

        var xFactor = 1f / sizeX;
        var yFactor = 1f / sizeY;

        for (int j = 0; j < sizeY; j++)
        {
            for (int i = 0; i < sizeX; i++)
            {
                pixels[i + j * sizeX] = src.GetPixelBilinear(i * xFactor, j * yFactor);
            }
        }

        ret.SetPixels(pixels);

        return ret;
    }


    /// <summary>
    /// 旋转 逆时针方向
    /// 仅支持 0 90 180 270 几个特定方向
    /// </summary>
    /// <param name="src"></param>
    /// <param name="angle"></param>
    /// <returns></returns>
    public static Texture2D roate(this Texture2D src, int angle)
    {
        var ret = src;

        var srcWidth = src.width;
        var srcHeight = src.height;

        if (angle == 90)
        {
            ret = new Texture2D(srcHeight, srcWidth, src.format, false, false);
            for (int i = 0; i < srcHeight; i++)
            {
                for (int j = 0; j < srcWidth; j++)
                {
                    ret.SetPixel(i, j, src.GetPixel(j, srcHeight - 1 - i));
                }
            }
        }
        else if (angle == 180)
        {
            ret = new Texture2D(srcWidth, srcHeight, src.format, false, false);
            for (int i = 0; i < srcWidth; i++)
            {
                for (int j = 0; j < srcHeight; j++)
                {
                    ret.SetPixel(i, j, src.GetPixel(srcWidth - 1 - i, srcHeight - 1 - j));
                }
            }
        }
        else if (angle == 270)
        {
            ret = new Texture2D(srcHeight, srcWidth, src.format, false, false);
            for (int i = 0; i < srcHeight; i++)
            {
                for (int j = 0; j < srcWidth; j++)
                {
                    ret.SetPixel(i, j, src.GetPixel(srcWidth / 2 + srcHeight / 2 - 1 - j, i));
                }
            }
        }

        return ret;
    }

    /// <summary>
    /// 合并
    /// </summary>
    /// <param name="src"></param>
    /// <param name="child"></param>
    /// <param name="sizeX"></param>
    /// <param name="sizeY"></param>
    /// <param name="centerPosX"></param>
    /// <param name="centerPosY"></param>
    /// <returns></returns>
    public static Texture2D combine(this Texture2D src, Texture2D child, int centerPosX, int centerPosY)
    {
        Texture2D ret = src;

        var sizeX = child.width;
        var sizeY = child.height;

        for (int i = centerPosX - sizeX / 2, m = 0; i < centerPosX + sizeX / 2; i++, m++)
        {
            for (int j = centerPosY - sizeY / 2, n = 0; j < centerPosY + sizeY / 2; j++, n++)
            {
                var color = child.GetPixel(m, n);
                if (color.a == 1)
                    ret.SetPixel(i, j, color);
            }
        }

        return ret;
    }

    /// <summary>
    /// 设置颜色
    /// </summary>
    /// <returns></returns>
    public static Texture2D setColor(this Texture2D src, Color color)
    {
        if (color == Color.white)
            return src;

        var sizeX = src.width;
        var sizeY = src.height;

        for (int i = 0; i < sizeX; i++)
        {
            for (int j = 0; j < sizeY; j++)
            {
                src.SetPixel(i, j, src.GetPixel(i, j) * color);
            }
        }
        return src;
    }

    /// <summary>
    /// 返回镜像后的图片
    /// </summary>
    /// <param name="src">原图片</param>
    /// <returns>镜像后的图片</returns>
    public static Texture2D mirror(this Texture2D src, bool isUpDown = false)
    {
        var srcWidth = src.width;
        var srcHeight = src.height;
        var ret = new Texture2D(srcWidth, srcHeight, src.format, false, false);
        if (!isUpDown)
        {
            for (int i = 0; i < srcWidth; i++)
            {
                for (int j = 0; j < srcHeight; j++)
                {
                    ret.SetPixel(srcWidth - 1 - i, j, src.GetPixel(i, j));
                }
            }
        }
        else
        {
            for (int i = 0; i < srcWidth; i++)
            {
                for (int j = 0; j < srcHeight; j++)
                {
                    ret.SetPixel(i, srcHeight - 1 - j, src.GetPixel(i, j));
                }
            }
        }

        return ret;
    }
}
